#include <iostream>
#include <string>
#include <errno.h>
#include <fstream>
#include <mutex>
#include <time.h>
#include <sys/time.h>
#include <boost/date_time/posix_time/posix_time.hpp>

#ifndef _error_message_hpp
#define _error_message_hpp

#define warn_message_str(str_msg)                         warning_message1((__FILE__),(__LINE__),(__FUNCTION__),(str_msg.c_str()))
#define warn_message(chars_msg)                           warning_message1((__FILE__),(__LINE__),(__FUNCTION__),(chars_msg))
#define error_message_str(str_msg)                         error_message1((__FILE__),(__LINE__),(__FUNCTION__),(str_msg.c_str()))
#define error_message(chars_msg)                           error_message1((__FILE__),(__LINE__),(__FUNCTION__),(chars_msg))
#define log_message_str(str_msg)                              log_message1((__FILE__),(__LINE__),(__FUNCTION__),(str_msg.c_str()))
#define log_message(chars_msg)                                log_message1((__FILE__),(__LINE__),(__FUNCTION__),(chars_msg))
#define logfile_message_str(str_msg,str_logfile)     logfile_message1((__FILE__),(__LINE__),(__FUNCTION__),(str_msg.c_str()),(str_logfile.c_str()))
#define logfile_message(chars_msg,chars_logfile) logfile_message1((__FILE__),(__LINE__),(__FUNCTION__),(chars_msg),(chars_logfile))
#define log_message_int(chars_int_name,int_in)   log_message_int1((__FILE__),(__LINE__),(__FUNCTION__),(chars_int_name),(int_in))

const unsigned char g_display_level_default = 8;
std::mutex  cout_mutex;


void now_str( std::string &str_datetime )
{
  time_t t;
  std::time(&t);
  boost::posix_time::ptime   ptime1 = boost::posix_time::from_time_t( t );
  str_datetime =  boost::posix_time::to_iso_extended_string( ptime1 );
  return;
}


unsigned long long now_useconds(void)
{
  struct timeval  tv1;
  gettimeofday(&tv1,NULL);
  unsigned long long  time_useconds   = tv1.tv_sec*1000000;
  time_useconds += tv1.tv_usec;
  return time_useconds;
}


void useconds_str(unsigned long long useconds, std::string &str_datetime_out)
{
  char char_useconds[8];
  time_t t_seconds;
  unsigned long long pure_useconds;

  t_seconds = useconds/1000000;
  pure_useconds = useconds%1000000;
  boost::posix_time::ptime   ptime1 = boost::posix_time::from_time_t( t_seconds );
  str_datetime_out =  boost::posix_time::to_iso_extended_string( ptime1 );
  str_datetime_out += ".";
  sprintf(char_useconds,"%06llu", pure_useconds);
  str_datetime_out += char_useconds;
  return;
}


void now_useconds_str( std::string &str_datetime_out )
{
  char char_useconds[8];
  struct timeval  tv1;
  gettimeofday(&tv1,NULL);

  boost::posix_time::ptime   ptime1 = boost::posix_time::from_time_t(  tv1.tv_sec );
  str_datetime_out =  boost::posix_time::to_iso_extended_string( ptime1 );
  str_datetime_out += ".";
  unsigned long long pure_useconds = tv1.tv_usec ;
  sprintf(char_useconds,"%06llu",  pure_useconds );
  str_datetime_out += char_useconds;
  return;
}


void u_duration_str(unsigned long long u_duration, std::string &str_duration)
{
  char                       char_out[32];
  unsigned long long seconds;
  unsigned long long pure_useconds;

  seconds = u_duration/1000000;
  pure_useconds = u_duration%1000000;

  sprintf( char_out, "%llu.%06llu", seconds, pure_useconds );
  str_duration = char_out;
  return;
}


void warning_message1(const char  *char_filename, int iline, const char* char_function,const char* char_msg)
{
  std::string str_datetime;
  now_useconds_str( str_datetime );
  std::string str_out =  "Warn:Time=";
  str_out += str_datetime;
  str_out += ", Line=";
  str_out += std::to_string(iline);
  str_out += ", File=\"";
  str_out += char_filename;
  str_out += "\", Func=\"";
  str_out += char_function;
  str_out +=  "\", Msg=\"";
  str_out += char_msg;
  str_out += "\"\r\n";

#ifdef use_cout_mutex
  std::lock_guard<std::mutex>  lock(cout_mutex);
#endif // use_cout_mutex

  std::cout  <<  str_out;
  return;
}


void error_message1(const char  *char_filename, int iline, const char* char_function,const char* char_msg)
{
  std::string str_datetime;
  now_useconds_str( str_datetime );
  std::string str_out =  "Err: Time=";
  str_out += str_datetime;
  str_out += ", Line=";
  str_out += std::to_string(iline);
  str_out += ", File=\"";
  str_out += char_filename;
  str_out += "\", Func=\"";
  str_out += char_function;
  str_out +=  "\", Msg=\"";
  str_out += char_msg;
  str_out += "\"\r\n";

#ifdef use_cout_mutex
  std::lock_guard<std::mutex>  lock(cout_mutex);
#endif // use_cout_mutex

  std::cout  <<  str_out;
  return;
}


void log_message1(const char  *char_filename, int iline, const char* char_function,const char* char_msg)
{
  std::string str_datetime;
  now_useconds_str( str_datetime );
  std::string str_out;
  str_out   = "Log: Time=";
  str_out += str_datetime;
  str_out += ", Line=";
  str_out += std::to_string(iline);
  str_out += ", File=\"";
  str_out += char_filename;
  str_out += "\", Func=\"";
  str_out += char_function;
  str_out +=  "\", Msg=\"";
  str_out += char_msg;
  str_out += "\"\r\n";

#ifdef use_cout_mutex
  std::lock_guard<std::mutex>  lock(cout_mutex);
#endif // use_cout_mutex

  std::cout  <<  str_out;
  return;
}


void log_message_int1( const char  *char_filename, int iline, const char* char_function, const char*  char_int_name, int int_ret )
{
  std::string str_datetime;
  now_useconds_str( str_datetime );
  std::string str_out;
  str_out   = "Log: Time=";
  str_out += str_datetime;
  str_out += ", Line=";
  str_out += std::to_string(iline);
  str_out += ", File=\"";
  str_out += char_filename;
  str_out += "\", Func=\"";
  str_out += char_function;
  str_out +=  "\", Msg=\"";
  str_out += char_int_name;
  str_out += "=";
  str_out += std::to_string(int_ret);
  str_out += "\"\r\n";

#ifdef use_cout_mutex
  std::lock_guard<std::mutex>  lock(cout_mutex);
#endif // use_cout_mutex

  std::cout  <<  str_out;
  return;
}


void logfile_message1(const char  *char_filename, int iline, const char* char_function,const char* char_msg, const char* char_logfile )
{
  static std::ofstream  ofs;
  static std::string str_logfile;

  std::string str_msg;
  std::string str_out;
  std::string str_datetime;
  now_useconds_str( str_datetime );

  if( str_logfile!=char_logfile && ofs.is_open() )  {
    ofs.close();
    }

  if(!ofs.is_open() ) {
    // append 方式打开无锁, 可以保证原子性
    ofs.open(char_logfile,std::ios_base::out|std::ios_base::app|std::ios_base::binary);
    if(!ofs.is_open())  {
      str_msg = "Write Open logfile ";
      str_msg +=   char_logfile;
      str_msg += " Failed.";
      error_message_str(str_msg);
      return;
      }
    }
  str_out   = "Log: Time=";
  str_out += str_datetime;
  str_out += ", Line=";
  str_out += std::to_string(iline);
  str_out += ", File=\"";
  str_out += char_filename;
  str_out += "\", Func=\"";
  str_out += char_function;
  str_out +=  "\", Msg=\"";
  str_out += char_msg;
  str_out += "\"\r\n";

  ofs  <<  str_out;
  return;
}


void append_str_msg_error(std::string &str_msg, int int_errno)
{
  if( int_errno==0)   return;

  std::string str_error =  strerror( int_errno ) ;
  if( str_error.length()>0)  {
    str_msg += "error=";
    str_msg += str_error;
    str_msg += ", errno=";
    str_msg += std::to_string(int_errno);
    return;
    }
  str_msg += "errno=";
  str_msg += std::to_string(int_errno);
  return;
}

#endif  /* error_message_hpp */
